{%mainunit bitcoin_p2p.pas}

{$IFDEF INTERFACE}

type
  { TMsgVersion is the first message to be sent after intial
    connetion. The connect*ing* client is expected to send this message
    immediately after conect, the connect*ed* client will not do
    anything until it received this }
  TMsgVersion = class(TMsg)
    Version: DWord;
    Services: UInt64;
    Timestamp: Int64;
    AddrMe: TNetAddress;
    AddrYou: TNetAddress;
    Nonce: UInt64;
    SubVersionNum: String;
    StartHeight: DWord;

    { The object will take ownership of the address objects and free them in its destructor }
    constructor Create(MyAddr, OtherAddr: TNetAddress; AStartHeight: DWord); overload;

    destructor Destroy; override;
    procedure ParseAndProcess; override;
    function Serialize: String; override;
    class function GetCommand: Tp2pCommand; override;
  end;

{$ENDIF}
{$IFDEF IMPLEMENTATION}

constructor TMsgVersion.Create(MyAddr, OtherAddr: TNetAddress; AStartHeight: DWord);
begin
  Version := 31402;  // we anounce ourself as this version.
  Services := 0;     // we provide no services.
  Timestamp := DateTimeToUnix(LocalTimeToUniversal(Now));
  AddrMe := MyAddr;
  AddrYou := OtherAddr;
  Nonce := VersionNonce;
  SubVersionNum := 'fpBitcoin / Turbo Bitcoin';
  StartHeight := AStartHeight;
end;

destructor TMsgVersion.Destroy;
begin
  if AddrMe <> nil then AddrMe.Free;
  if AddrYou <> nil then AddrYou.Free;
  inherited Destroy;
end;

procedure TMsgVersion.ParseAndProcess;
begin
  AddrMe := nil;
  AddrYou := nil;
  Version := ReadDWord;
  Services := ReadQWord;
  Timestamp := ReadQWord;
  AddrMe := TNetAddress.Create(FPeer, FReceiveData);
  AddrMe.ParseAndProcess;
  if Version >= 106 then begin
    AddrYou := TNetAddress.Create(FPeer, FReceiveData);
    AddrYou.ParseAndProcess;
    Nonce := ReadQWord;
    SubVersionNum := ReadVarStr;
    if Version >= 209 then begin
      StartHeight := ReadDWord;
    end;
  end;

  if Nonce = VersionNonce then
    raise Exception.Create('connection from ourselves');

  FPeer.OnVersion(Self);
end;

function TMsgVersion.Serialize: String;
begin
  FSendData := TStringStream.Create('');

  WriteDWord(Version);
  WriteQWord(Services);
  WriteQWord(Timestamp);
  AddrMe.SerializeToStream(FSendData);
  AddrYou.SerializeToStream(FSendData);
  WriteQWord(Nonce);
  WriteVarStr(SubVersionNum);
  WriteDWord(StartHeight);

  Result := WrapHeader(FSendData.DataString, True);
  FSendData.Free;
end;

class function TMsgVersion.GetCommand: Tp2pCommand;
begin
  Result := 'version'#0#0#0#0#0;
end;

{$ENDIF}
